package com.cpms.framework.common.core.caffeine;

import com.github.benmanes.caffeine.cache.Caffeine;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @description: ：初始化缓存管理器
 * @author: gulang
 * @time: 2023/12/8
 */

@Configuration
@Order(1)
@EnableConfigurationProperties(CaffeineProperty.class)
public class CaffeineConfiguration {
    private final Logger log = LoggerFactory.getLogger(CaffeineConfiguration.class);
    @Resource
    private CaffeineProperty caffeineProperty;

    private static  int DEFAULT_INITCAPACITY = 100;

    private static  long DEFAULT_MAX_IMUMSIZE = 1000;

    private static long DEFAULT_EXPIREAFTERACCESS = 60;

    private static long DEFAULT_EXPIREAFTERWRITE = 60;

    private static String DEFAULT_CACHE_NAME = "commonCache";

    private static TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;

    /**
     * 创建基于Caffeine的Cache Manager
     * 初始化一些key存入
     * @return
     */
    //配置CacheManager
    @Bean(name = "caffeineCacheManager")
    @Primary
    public CacheManager cacheManagerWithCaffeine() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        // 遍历配置中的缓存配置项，并为每个缓存配置不同的过期策略
        Map<String, CaffeineProperty.PropConfig> caches = caffeineProperty.getCaches();
        if(caches == null) {
            Map<String, CaffeineProperty.PropConfig>  defaultCache = new HashMap();
            CaffeineProperty.PropConfig defaultProp = new CaffeineProperty.PropConfig();
            defaultProp.setTimeUnit(DEFAULT_TIME_UNIT);
            defaultCache.put(DEFAULT_CACHE_NAME,defaultProp);
            caches = defaultCache;
        }
        caches.forEach((cacheName, cacheConfig) -> {
            Caffeine<Object, Object> caffeineBuilder = Caffeine.newBuilder();
                    //cache的初始容量值，表示的是 k-value键值对的个数
            caffeineBuilder.initialCapacity(cacheConfig.getInitCapacity()== null ? DEFAULT_INITCAPACITY : cacheConfig.getInitCapacity());
                    //maximumSize用来控制cache的最大缓存数量，表示的是 k-value键值对的个数
            caffeineBuilder.maximumSize(cacheConfig.getMaximumSize() == null ? DEFAULT_MAX_IMUMSIZE : cacheConfig.getMaximumSize());

            /**
             * 当同时设置了 expireAfterAccess 和 expireAfterWrite 时，Caffeine 缓存会采用两者中的较早的过期时间
             * 如： expireAfterAccess(5, TimeUnit.MINUTES) 和 expireAfterWrite(10, TimeUnit.MINUTES)，那么缓存项将在创建或者最后一次写入后的5分钟内过期。
             */
            if(cacheConfig.getExpireAfterWrite() == null && cacheConfig.getExpireAfterAccess() == null) {
                //最后一次写入后多长时间过期,
                caffeineBuilder.expireAfterWrite( DEFAULT_EXPIREAFTERWRITE , cacheConfig.getTimeUnit() == null ? DEFAULT_TIME_UNIT : cacheConfig.getTimeUnit());
            }
            if(cacheConfig.getExpireAfterWrite() != null) {
                //最后一次写入后多长时间过期,
                caffeineBuilder.expireAfterWrite( cacheConfig.getExpireAfterWrite() , cacheConfig.getTimeUnit() == null ? DEFAULT_TIME_UNIT : cacheConfig.getTimeUnit());
            }

            if(cacheConfig.getExpireAfterAccess() != null) {
                //最后一次写入或者访问后多久过期，每次写入或访问过期时间会重新计算
                caffeineBuilder.expireAfterAccess( cacheConfig.getExpireAfterAccess() , cacheConfig.getTimeUnit() == null ? DEFAULT_TIME_UNIT : cacheConfig.getTimeUnit());
            }
            cacheManager.registerCustomCache(cacheName, caffeineBuilder.build());
        });
        // 是否允许值为空
        cacheManager.setAllowNullValues(false);
        log.info("====================== caffeine init complete, cacheNames:{} ======================",caches.keySet());
        return cacheManager;

    }
}
